// DicMgmt.cpp : Implementation of CDicMgmt

#include "stdafx.h"
#include "DicMgmt.h"
#include "common.h"
#include <atlpath.h>


// CDicMgmt

STDMETHODIMP CDicMgmt::InterfaceSupportsErrorInfo(REFIID riid)
{
	static const IID* const arr[] = 
	{
		&IID_IDicMgmt
	};

	for (int i=0; i < sizeof(arr) / sizeof(arr[0]); i++)
	{
		if (InlineIsEqualGUID(*arr[i],riid))
			return S_OK;
	}
	return S_FALSE;
}


STDMETHODIMP CDicMgmt::CreateDicFile(BSTR bstrFile, BSTR bstrPassword)
{
	// TODO: Add your implementation code here
	HRESULT				hr					 = S_OK;	// Error code reporting
	DBPROPSET			dbpropset[2];					// Property Set used to initialize provider
	DBPROP				dbprop[1];						// property array used in property set to initialize provider
	DBPROP             sscedbprop[3]; // Property array for security and case-sensitivity properties.
	IDBInitialize	    *pIDBInitialize      = NULL;    // Provider Interface Pointer
	IDBDataSourceAdmin	*pIDBDataSourceAdmin = NULL;	// Provider Interface Pointer
	IUnknown			*pIUnknownSession	 = NULL;	// Provider Interface Pointer
	IDBCreateCommand	*pIDBCrtCmd			 = NULL;	// Provider Interface Pointer
	ICommandText		*pICmdText			 = NULL;	// Provider Interface Pointer
	IDBCreateSession	*pIDBCreateSession	 = NULL;  // The IDBCreateSession interface

	CComBSTR file(bstrFile), password(bstrPassword);
	CString strDrop, strCreate;
	CString message;

	if(!bstrFile)
	{
		hr=E_INVALIDARG;
		message= _TEXT("invalid database file name ");
		goto CLEANUP;
	}

	if(!bstrPassword)
	{
		hr=E_INVALIDARG;
		message= _TEXT("black password is not allowed");
		goto CLEANUP;
	}

	// Delete the DB if it already exists
	//
	if(!DeleteFile(file))
	{
		DWORD dwResult=::GetLastError();
		if(dwResult!=ERROR_FILE_NOT_FOUND)
		{
			message.Format(_TEXT("[DicMgmt]Failed to delete database file: %d"), dwResult);
			
			hr=HRESULT_FROM_WIN32(dwResult);
			goto CLEANUP;
		}
	}

	VariantInit(&dbprop[0].vValue);
	for (int i = 0; i < sizeof(sscedbprop) / sizeof(sscedbprop[0]); i++)
    {
       VariantInit(&sscedbprop[i].vValue);
    }

   	// Create an instance of the OLE DB Provider
	//
	hr = CoCreateInstance(	CLSID_SQLSERVERCE, 
							0, 
							CLSCTX_INPROC_SERVER, 
							IID_IDBInitialize, 
							(void**)&pIDBInitialize);
	if(FAILED(hr))
	{
		message.Format(_TEXT("[DicMgmt]Failed to create SQLCE object: %d"), hr);
		goto CLEANUP;
	}

	// Initialize a property with name of database
	//
	dbprop[0].dwPropertyID		= DBPROP_INIT_DATASOURCE;
	dbprop[0].dwOptions			= DBPROPOPTIONS_REQUIRED;
	dbprop[0].vValue.vt			= VT_BSTR;
	dbprop[0].vValue.bstrVal	= SysAllocString(file);
	if(NULL == dbprop[0].vValue.bstrVal)
	{
		message.Format(_TEXT("[DicMgmt]Failed to allocate memory for dbprop string"));
		hr = E_OUTOFMEMORY;	
		goto CLEANUP;
	}

	// Specify the encryption mode. 
	sscedbprop[0].dwPropertyID = DBPROP_SSCE_ENCRYPTIONMODE;
	sscedbprop[0].dwOptions = DBPROPOPTIONS_REQUIRED;
	sscedbprop[0].vValue.vt = VT_I4;
	sscedbprop[0].vValue.intVal = DBPROPVAL_SSCE_EM_PLATFORM_DEFAULT;

	// Specify the strong password.
	sscedbprop[1].dwPropertyID = DBPROP_SSCE_DBPASSWORD;
	sscedbprop[1].dwOptions = DBPROPOPTIONS_REQUIRED;
	sscedbprop[1].vValue.vt = VT_BSTR;
	sscedbprop[1].vValue.bstrVal = SysAllocString(password);

	if(NULL == sscedbprop[1].vValue.bstrVal)
	{
		message.Format(_TEXT("[DicMgmt]Failed to allocate memory for password string"));
		hr = E_OUTOFMEMORY;
		goto CLEANUP;
	}

   // Set the case sensitivity to true.
   sscedbprop[2].dwPropertyID  = DBPROP_SSCE_DBCASESENSITIVE;
   sscedbprop[2].dwOptions   = DBPROPOPTIONS_REQUIRED;
   sscedbprop[2].vValue.vt   = VT_BOOL;
   sscedbprop[2].vValue.boolVal = VARIANT_TRUE;


	// Initialize the property set
	//
	dbpropset[0].guidPropertySet = DBPROPSET_DBINIT;
	dbpropset[0].rgProperties	 = dbprop;
	dbpropset[0].cProperties	 = sizeof(dbprop)/sizeof(dbprop[0]);

	dbpropset[1].guidPropertySet = DBPROPSET_SSCE_DBINIT ;
	dbpropset[1].rgProperties  = sscedbprop;
	dbpropset[1].cProperties  = sizeof(sscedbprop)/sizeof(sscedbprop[0]);

	// Get IDBDataSourceAdmin interface
	//
	hr = pIDBInitialize->QueryInterface(IID_IDBDataSourceAdmin, (void **) &pIDBDataSourceAdmin);
	if(FAILED(hr))
	{
		GetSQLCEErrors(message);
		goto CLEANUP;
	}

	// Create and initialize data store
	//
	hr = pIDBDataSourceAdmin->CreateDataSource(sizeof(dbpropset)/sizeof(dbpropset[0]), dbpropset, NULL, IID_IUnknown, &pIUnknownSession);
	if(FAILED(hr))	
    {
		GetSQLCEErrors(message);
		goto CLEANUP;
    }

    // Get IDBCreateSession interface
    //
  	hr = pIDBInitialize->QueryInterface(IID_IDBCreateSession, (void**)&pIDBCreateSession);
	if(FAILED(hr))
	{
		GetSQLCEErrors(message);
		// Throw the error
		goto CLEANUP;
	}

	// Get IDBCreateCommand interface
	//
	hr = pIUnknownSession->QueryInterface(IID_IDBCreateCommand, (void**)&pIDBCrtCmd);
	if(FAILED(hr))
	{
		GetSQLCEErrors(message);
		// Throw the error
		goto CLEANUP;
	}

	// Create a command object
	//
	hr = pIDBCrtCmd->CreateCommand(NULL, IID_ICommandText, (IUnknown**)&pICmdText);
	if(FAILED(hr))
	{
		GetSQLCEErrors(message);
		// Throw the error
		goto CLEANUP;
	}

	// Drop  table if it exists ignoring errors
	//
	strDrop.Format(SQL_DROP_WUBI_CODE_TABLE, CODE_TABLE);
	hr=ExecuteSQL(pICmdText, CT2W(strDrop));
	//strDrop.Format(SQL_DROP_WUBI_CODE_TABLE, USER_CODE);
	//hr=ExecuteSQL(pICmdText, CT2W(strDrop));
	// skip check the HR. usually, if no table, it will return "no tables". this is not an error conditon.

	// Create  table
	//
	strCreate.Format(SQL_CREATE_WUBI_SYS_CODE_TABLE, CODE_TABLE);
	hr = ExecuteSQL(pICmdText, CT2W(strCreate));
	if(FAILED(hr))
	{
		GetSQLCEErrors(message);
		// Throw the error
		goto CLEANUP;
	}
		

	// Create Index
	// Note: The sample table has small amount of demo data, the index is created here.
	// In your application, to improve performance, index shoule be created after 
	// inserting initial data. 
	//
	//strCreateIndex.Format(SQL_CREATE_WUBICODE_INDEX, 
	//hr = ExecuteSQL(pICmdText, (LPWSTR)SQL_CREATE_WUBICODE_INDEX);

CLEANUP:
    // Clear Variant
    //
	VariantClear(&dbprop[0].vValue);
	VariantClear(&sscedbprop[1].vValue);

	// Release interfaces
	//
	if(pICmdText)
	{
		pICmdText->Release();
	}

	if(pIDBCrtCmd)
	{
		pIDBCrtCmd->Release();
	}

	if(pIDBCreateSession)
	{
		pIDBCreateSession->Release();
	}

	if(pIUnknownSession)
	{
		pIUnknownSession->Release();
	}

	if(pIDBDataSourceAdmin)
	{
		pIDBDataSourceAdmin->Release();
	}

	if(pIDBInitialize)
	{
		pIDBInitialize->Release();
	}

	if(FAILED(hr))
		AtlReportError(__uuidof(DicMgmt),message,IID_IDicMgmt,hr);
	return hr;
	
}

HRESULT CDicMgmt::ExecuteSQL(ICommandText *pICmdText, WCHAR * pwszQuery)
{
	HRESULT hr = NOERROR;

	hr = pICmdText->SetCommandText(DBGUID_SQL, pwszQuery); 
	if(FAILED(hr))
	{
		CString message;
		GetSQLCEErrors(message);
		// Throw the error
		AtlReportError(__uuidof(DicMgmt), message,IID_IDicMgmt,hr);
		goto CLEANUP;
	}

	hr = pICmdText->Execute(NULL, IID_NULL, NULL, NULL, NULL);

CLEANUP:
	return hr;
}

HRESULT CDicMgmt::GetSQLCEErrors(CString& message)
{
    static TCHAR *sErrIErrorInfo     = L"IErrorInfo interface";
    static TCHAR *sErrIErrorRecords  = L"IErrorRecords interface";
    static TCHAR *sErrRecordCount    = L"error record count";
    static TCHAR *sErrInfo           = L"ERRORINFO structure";
    static TCHAR *sErrStandardInfo   = L"standard error info";
    static TCHAR *sErrDescription    = L"standard error description";
    static TCHAR *sErrNoSource       = L"error source";

    HRESULT hr                          = S_OK;
    IErrorInfo       *pIErrorInfo       = NULL;
    IErrorRecords    *pIErrorRecords    = NULL;
    ERRORINFO        errorInfo          = { 0 };
    IErrorInfo       *pIErrorInfoRecord = NULL;
	
	message.Empty();

    try
    {
        // This interface supports returning error information.
        // Get the error object from the system for the current
        // thread.
        hr = GetErrorInfo(0, &pIErrorInfo);
        if ( hr == S_FALSE )
        {
            message.Format(_TEXT("No error occured.\n"));
            return S_OK;
        }

        if(FAILED(hr) || NULL == pIErrorInfo)
            throw sErrIErrorInfo;

        // The error records are retrieved from the IIErrorRecords
        // interface, which can be obtained from the IErrorInfo
        // interface.
        hr = pIErrorInfo->QueryInterface(IID_IErrorRecords,
            (void **) &pIErrorRecords);
        if ( FAILED(hr) || NULL == pIErrorRecords )
            throw sErrIErrorRecords;

        // The IErrorInfo interface is no longer required because
        // we have the IErrorRecords interface, relase it.
        pIErrorInfo->Release();
        pIErrorInfo = NULL;

        ULONG ulNumErrorRecs = 0;

        // Determine the number of records in this error object
        hr = pIErrorRecords->GetRecordCount(&ulNumErrorRecs);
        if ( FAILED(hr) )
            throw sErrRecordCount;

		CString temp;
        // Loop over each error record in the error object to display 
        // information about each error. Errors are returned. 
        for (DWORD dwErrorIndex = 0;
             dwErrorIndex < ulNumErrorRecs;
             dwErrorIndex++)
        {
            // Retrieve basic error information for this error.
            hr = pIErrorRecords->GetBasicErrorInfo(dwErrorIndex,
              &errorInfo);
            if ( FAILED(hr) )
                throw sErrInfo;

            TCHAR szCLSID[64]  = { 0 };
            TCHAR szIID[64]    = { 0 };
            TCHAR szDISPID[64] = { 0 };

            StringFromGUID2(errorInfo.clsid, (LPOLESTR)szCLSID,
                sizeof(szCLSID));
            StringFromGUID2(errorInfo.iid, (LPOLESTR)szIID,
                sizeof(szIID));
			
            message.Format(_TEXT("HRESULT           = %lx\n"), errorInfo.hrError);
			temp.Format(_TEXT("clsid             = %s\n"), szCLSID);
            message+=temp;
			temp.Format(_TEXT("iid               = %s\n"), szIID);
            message+=temp;
			temp.Format(_TEXT("dispid            = %ld\n"), errorInfo.dispid);
            message+=temp;
			temp.Format(_TEXT("Native Error Code = %lx\n"), errorInfo.dwMinor);
            message+=temp;

            // Retrieve standard error information for this error.
            hr = pIErrorRecords->GetErrorInfo(dwErrorIndex, NULL,
                &pIErrorInfoRecord);

            if ( FAILED(hr) )
                throw sErrStandardInfo;

            CComBSTR bstrDescriptionOfError;
            CComBSTR bstrSourceOfError;

            // Get the description of the error.
            hr = pIErrorInfoRecord->GetDescription(&bstrDescriptionOfError);
            if ( FAILED(hr) )
                throw sErrDescription;

            temp.Format(_TEXT("Description = %s\n"), bstrDescriptionOfError);
			message+=temp;

            // Get the source of the error.
            hr = pIErrorInfoRecord->GetSource(&bstrSourceOfError);
            if ( FAILED(hr) )
                throw sErrNoSource;

            temp.Format(_TEXT("Description = %s\n"), bstrSourceOfError);
			message+=temp;

            // This interface variable will be used the next time 
            // though this loop. In the last error case this interface 
            // is no longer needed so we must release it.
            if(NULL != pIErrorInfoRecord)
                pIErrorInfoRecord->Release();
            pIErrorInfoRecord = NULL;
        }
    }
    catch( TCHAR *szMsg )
    {
		CString temp;
        temp.Format(_TEXT("Failed to retrieve "));
		temp.Format(_TEXT("%s"),szMsg);
        message+=temp;
    }

    if( pIErrorInfoRecord )
        pIErrorInfoRecord->Release();

    if ( pIErrorInfo )
        pIErrorInfo->Release();

    if ( pIErrorRecords )
        pIErrorRecords->Release();

    return hr;
}


STDMETHODIMP CDicMgmt::OpenConnection(BSTR bstrDbFile, BSTR bstrPassword)
{
	HRESULT			   	hr				= S_OK;	// Error code reporting
	DBPROPSET			dbpropset[2];					// Property Set used to initialize provider
	DBPROP				dbprop[1];						// property array used in property set to initialize provider
	DBPROP             sscedbprop[3]; // Property array for security and case-sensitivity properties.

    IDBInitialize       *pIDBInitialize = NULL;		// Provider Interface Pointer
	IDBProperties       *pIDBProperties	= NULL;		// Provider Interface Pointer

	CString message;

	if(!bstrDbFile)
	{
		hr=E_INVALIDARG;
		message= _TEXT("invalid database file name ");
		goto CLEANUP;
	}

	if(!bstrPassword)
	{
		hr=E_INVALIDARG;
		message= _TEXT("black password is not allowed");
		goto CLEANUP;
	}

	if(!ATLPath::FileExists(bstrDbFile))
	{
		hr=E_INVALIDARG;
		message= _TEXT("database files doesn't exist");
		goto CLEANUP;
	}

	VariantInit(&dbprop[0].vValue);
	for (int i = 0; i < sizeof(sscedbprop) / sizeof(sscedbprop[0]); i++)
    {
       VariantInit(&sscedbprop[i].vValue);
    }

    // Create an instance of the OLE DB Provider
	//
	hr = CoCreateInstance(	CLSID_SQLSERVERCE, 
							0, 
							CLSCTX_INPROC_SERVER, 
							IID_IDBInitialize, 
							(void**)&pIDBInitialize);
	if(FAILED(hr))
	{
		message.Format(_TEXT("[DicMgmt]Failed to creatre CLSID_SQLSERVERCE object"));
		goto CLEANUP;
	}

	// Initialize a property with name of database
	//
    dbprop[0].dwPropertyID	= DBPROP_INIT_DATASOURCE;
	dbprop[0].dwOptions		= DBPROPOPTIONS_REQUIRED;
    dbprop[0].vValue.vt		= VT_BSTR;
    dbprop[0].vValue.bstrVal= SysAllocString(bstrDbFile);
	if(NULL == dbprop[0].vValue.bstrVal)
	{
		message.Format(_TEXT("[DicMgmt]Failed to allocate memory for db file string"));
		hr = E_OUTOFMEMORY;
		goto CLEANUP;
	}

	// Specify the encryption mode. 
	sscedbprop[0].dwPropertyID = DBPROP_SSCE_ENCRYPTIONMODE;
	sscedbprop[0].dwOptions = DBPROPOPTIONS_REQUIRED;
	sscedbprop[0].vValue.vt = VT_I4;
	sscedbprop[0].vValue.intVal = DBPROPVAL_SSCE_EM_PLATFORM_DEFAULT;

	// Specify the strong password.
	sscedbprop[1].dwPropertyID = DBPROP_SSCE_DBPASSWORD;
	sscedbprop[1].dwOptions = DBPROPOPTIONS_REQUIRED;
	sscedbprop[1].vValue.vt = VT_BSTR;
	sscedbprop[1].vValue.bstrVal = SysAllocString(bstrPassword);

	if(NULL == sscedbprop[1].vValue.bstrVal)
	{
		message.Format(_TEXT("[DicMgmt]Failed to allocate memory for password string"));
		hr = E_OUTOFMEMORY;
		goto CLEANUP;
	}

   // Set the case sensitivity to true.
   sscedbprop[2].dwPropertyID  = DBPROP_SSCE_DBCASESENSITIVE;
   sscedbprop[2].dwOptions   = DBPROPOPTIONS_REQUIRED;
   sscedbprop[2].vValue.vt   = VT_BOOL;
   sscedbprop[2].vValue.boolVal = VARIANT_TRUE;

	// Initialize the property set
	//
	dbpropset[0].guidPropertySet = DBPROPSET_DBINIT;
	dbpropset[0].rgProperties	 = dbprop;
	dbpropset[0].cProperties	 = sizeof(dbprop)/sizeof(dbprop[0]);

	dbpropset[1].guidPropertySet = DBPROPSET_SSCE_DBINIT ;
	dbpropset[1].rgProperties  = sscedbprop;
	dbpropset[1].cProperties  = sizeof(sscedbprop)/sizeof(sscedbprop[0]);

	//Set initialization properties.
	//
	hr = pIDBInitialize->QueryInterface(IID_IDBProperties, (void **)&pIDBProperties);
    if(FAILED(hr))
    {
		GetSQLCEErrors(message);
		goto CLEANUP;
    }

	// Sets properties in the Data Source and initialization property groups
	//
    hr = pIDBProperties->SetProperties(sizeof(dbpropset)/sizeof(dbpropset[0]), dbpropset); 
	if(FAILED(hr))
    {
		GetSQLCEErrors(message);
		goto CLEANUP;
    }

	// Initializes a data source object 
	//
	hr = pIDBInitialize->Initialize();
	if(FAILED(hr))
    {
		GetSQLCEErrors(message);
		goto CLEANUP;
    }

    // Get IDBCreateSession interface
    //
  	hr = pIDBInitialize->QueryInterface(IID_IDBCreateSession, (void**)&m_pIDBCreateSession);
	if(FAILED(hr))
	{
		GetSQLCEErrors(message);
		goto CLEANUP;
	}

CLEANUP:
    // Clear Variant
    //
	VariantClear(&dbprop[0].vValue);
	VariantClear(&sscedbprop[1].vValue);

	// Release interfaces
	//
	if(pIDBProperties)
	{
		pIDBProperties->Release();
	}

    if (pIDBInitialize)
    {
        pIDBInitialize->Release();
    }
	if(FAILED(hr))
		AtlReportError(__uuidof(DicMgmt),message,IID_IDicMgmt,hr);
	return hr;
}


STDMETHODIMP CDicMgmt::AddWubiCode(BSTR wubiCode, BSTR pinyinCode, BSTR GBChars, LONG displayOrder, VARIANT_BOOL IsSystemCode)
{
	// Declarations
	HRESULT                  hr;
	ICommandText *           pICmdText         = NULL;
	IDBCreateCommand *       pIDBCrtCmd        = NULL;
	ICommandPrepare *        pICmdPrepare      = NULL;
	ICommandWithParameters * pICmdWParams      = NULL;
	IAccessor *              pIAcc             = NULL;
	ULONG                    cParams;
	DBPARAMINFO *            rgParamInfo       = NULL;
	OLECHAR *                pNamesBuffer      = NULL;
	ULONG                    cBindings;
	DBBINDING                rgBindings[5];
	ULONG                    cbRowSize;
	HACCESSOR                hAcc;
	BYTE *                   pData             = NULL;
	DBPARAMS                 params;
	LONG                     cRowsAffected;

	CString strSQL,message;

	
	hr = m_pIDBCreateSession->CreateSession(NULL, IID_IDBCreateCommand,
		(IUnknown**) &pIDBCrtCmd);
	if (FAILED(hr))
	{
		//Send an error-specific message and do error handling.
		GetSQLCEErrors(message);
		goto CLEANUP;
	}


	// Create the new command that uses parameters.
	hr = pIDBCrtCmd->CreateCommand(NULL, IID_ICommandWithParameters,
		(IUnknown**) &pICmdWParams);
	if (FAILED(hr))
	{
		//Send an error-specific message and do error handling.
		GetSQLCEErrors(message);
		goto CLEANUP;
	}

	hr = pICmdWParams->QueryInterface(IID_ICommandText, (void**) &pICmdText);
	if (FAILED(hr))
	{
		//Send an error-specific message and do error handling.
		GetSQLCEErrors(message);
		goto CLEANUP;
	}

	hr = pICmdWParams->QueryInterface(IID_ICommandPrepare, (void**) &pICmdPrepare);
	if (FAILED(hr))
	{
		//Send an error-specific message and do error handling.
		GetSQLCEErrors(message);
		goto CLEANUP;
	}

	// Specify the command text using parameter markers in the query syntax.
	strSQL.Format(SQL_INSERT_WUBI_CODE,CODE_TABLE);
	hr = pICmdText->SetCommandText(DBGUID_DBSQL, strSQL);
	if (FAILED(hr))
	{
		//Send an error-specific message and do error handling.
		GetSQLCEErrors(message);
		goto CLEANUP;
	}

	// Prepare the current command.
	hr = pICmdPrepare->Prepare(0);
	if (FAILED(hr))
	{
		//Send an error-specific message and do error handling.
		GetSQLCEErrors(message);
		goto CLEANUP;
	}

	// Retrieving parameter information
	hr = pICmdWParams->GetParameterInfo(&cParams, &rgParamInfo, &pNamesBuffer);
	if (FAILED(hr))
	{
		//Send an error-specific message and do error handling.
		GetSQLCEErrors(message);
		goto CLEANUP;
	}

	// Create the acessor object and column specific bindings.

	hr = pICmdText->QueryInterface(IID_IAccessor, (void**) &pIAcc);
	if (FAILED(hr))
	{
		//Send an error-specific message and do error handling.
		GetSQLCEErrors(message);
		goto CLEANUP;
	}

	// Create the bindings for the three columns.
	cBindings = 5;

	rgBindings[0].iOrdinal = 1;
	rgBindings[0].obStatus = 0;
	rgBindings[0].obLength = rgBindings[0].obStatus + sizeof(DBSTATUS);
	rgBindings[0].obValue = rgBindings[0].obLength + sizeof(ULONG);
	rgBindings[0].pTypeInfo = NULL;
	rgBindings[0].pObject = NULL;
	rgBindings[0].pBindExt = NULL;
	rgBindings[0].dwPart = DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS;
	rgBindings[0].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
	rgBindings[0].eParamIO = DBPARAMIO_INPUT;
	rgBindings[0].cbMaxLen = 20 * sizeof(WCHAR); //WubiCode is nvarchar(20)
	rgBindings[0].dwFlags = 0;
	rgBindings[0].wType = DBTYPE_WSTR;
	rgBindings[0].bPrecision = 0;
	rgBindings[0].bScale = 0;

	rgBindings[1].iOrdinal = 2;
	rgBindings[1].obStatus = rgBindings[0].obValue + rgBindings[0].cbMaxLen;
	rgBindings[1].obLength = rgBindings[1].obStatus + sizeof(DBSTATUS);
	rgBindings[1].obValue = rgBindings[1].obLength + sizeof(ULONG);
	rgBindings[1].pTypeInfo = NULL;
	rgBindings[1].pObject = NULL;
	rgBindings[1].pBindExt = NULL;
	rgBindings[1].dwPart = DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS;
	rgBindings[1].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
	rgBindings[1].eParamIO = DBPARAMIO_INPUT;
	rgBindings[1].cbMaxLen = 40 * sizeof(WCHAR); //PinYinCode is nvarchar(40)
	rgBindings[1].dwFlags = 0;
	rgBindings[1].wType = DBTYPE_WSTR;
	rgBindings[1].bPrecision = 0;
	rgBindings[1].bScale = 0;

	rgBindings[2].iOrdinal = 3;
	rgBindings[2].obStatus = rgBindings[1].obValue + rgBindings[1].cbMaxLen;
	rgBindings[2].obLength = rgBindings[2].obStatus + sizeof(DBSTATUS);
	rgBindings[2].obValue = rgBindings[2].obLength + sizeof(ULONG);
	rgBindings[2].pTypeInfo = NULL;
	rgBindings[2].pObject = NULL;
	rgBindings[2].pBindExt = NULL;
	rgBindings[2].dwPart = DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS;
	rgBindings[2].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
	rgBindings[2].eParamIO = DBPARAMIO_INPUT;
	rgBindings[2].cbMaxLen = 40 * sizeof(WCHAR); //GBChars is nvarchar(20)
	rgBindings[2].dwFlags = 0;
	rgBindings[2].wType = DBTYPE_WSTR;
	rgBindings[2].bPrecision = 0;
	rgBindings[2].bScale = 0;

	rgBindings[3].iOrdinal = 4;
	rgBindings[3].obStatus = rgBindings[2].obValue + rgBindings[1].cbMaxLen;
	rgBindings[3].obLength = rgBindings[3].obStatus + sizeof(DBSTATUS);
	rgBindings[3].obValue = rgBindings[3].obLength + sizeof(ULONG);
	rgBindings[3].pTypeInfo = NULL;
	rgBindings[3].pObject = NULL;
	rgBindings[3].pBindExt = NULL;
	rgBindings[3].dwPart = DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS;
	rgBindings[3].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
	rgBindings[3].eParamIO = DBPARAMIO_INPUT;
	rgBindings[3].cbMaxLen = sizeof(int); //DisplayOrder is int. even in 64bit, it is 4bit
	rgBindings[3].dwFlags = 0;
	rgBindings[3].wType = DBTYPE_I4;
	rgBindings[3].bPrecision = 0;
	rgBindings[3].bScale = 0;

	rgBindings[4].iOrdinal = 5;
	rgBindings[4].obStatus = rgBindings[3].obValue + rgBindings[1].cbMaxLen;
	rgBindings[4].obLength = rgBindings[4].obStatus + sizeof(DBSTATUS);
	rgBindings[4].obValue = rgBindings[4].obLength + sizeof(ULONG);
	rgBindings[4].pTypeInfo = NULL;
	rgBindings[4].pObject = NULL;
	rgBindings[4].pBindExt = NULL;
	rgBindings[4].dwPart = DBPART_VALUE | DBPART_LENGTH | DBPART_STATUS;
	rgBindings[4].dwMemOwner = DBMEMOWNER_CLIENTOWNED;
	rgBindings[4].eParamIO = DBPARAMIO_INPUT;
	rgBindings[4].cbMaxLen = sizeof(char); //IsSystemCode is bit. even in 64bit, it is 4bit
	rgBindings[4].dwFlags = 0;
	rgBindings[4].wType = DBTYPE_I1;
	rgBindings[4].bPrecision = 0;
	rgBindings[4].bScale = 0;

	// Calculate the total memory needed for the input buffer.
	cbRowSize = rgBindings[4].obValue + rgBindings[4].cbMaxLen;
	cbRowSize=ROUNDUP(cbRowSize);

	// Create the accessor for the parameter data. 
	hr = pIAcc->CreateAccessor(DBACCESSOR_PARAMETERDATA, cBindings, rgBindings, cbRowSize, &hAcc, NULL);
	if (FAILED(hr))
	{
		//Send an error-specific message and do error handling.
		GetSQLCEErrors(message);
		goto CLEANUP;
	}

	// Allocate memory for the parameter data.
	pData = (BYTE*) malloc(cbRowSize);
	if(!(pData))
	{
		message.Format(_TEXT("fail to allocate memory for row data"));
		hr = E_OUTOFMEMORY;
		goto CLEANUP; 
	}

	//Clear out the buffer.
	memset(pData, 0, cbRowSize);
 
	// Define the insert data for the parameters.
	// WubiCode
	* (DBSTATUS*) (pData + rgBindings[0].obStatus) = DBSTATUS_S_OK;
	wcscpy_s((WCHAR*)(pData + rgBindings[0].obValue), 20, wubiCode); 
	* (ULONG*)   (pData + rgBindings[0].obLength) = sizeof(WCHAR)*wcslen(wubiCode);

	// pinyinCode
	* (DBSTATUS*) (pData + rgBindings[1].obStatus) = DBSTATUS_S_OK;
	wcscpy_s((WCHAR*) (pData + rgBindings[1].obValue), 40, pinyinCode);
	* (int*)   (pData + rgBindings[1].obLength)  = wcslen(pinyinCode) * sizeof(WCHAR);

	// GBChars
	* (DBSTATUS*) (pData + rgBindings[2].obStatus) = DBSTATUS_S_OK;
	wcscpy_s((WCHAR*) (pData + rgBindings[2].obValue), 40, GBChars);
	* (int*)   (pData + rgBindings[2].obLength)  = wcslen(GBChars) * sizeof(WCHAR);

	// display order
	* (DBSTATUS*) (pData + rgBindings[2].obStatus) = DBSTATUS_S_OK;
	* (int*)(pData + rgBindings[2].obValue)=displayOrder;
	* (int*)   (pData + rgBindings[2].obLength)  = sizeof(int);

	// GBChars
	* (DBSTATUS*) (pData + rgBindings[2].obStatus) = DBSTATUS_S_OK;
	* (int*)(pData + rgBindings[2].obValue)=IsSystemCode;
	* (int*)   (pData + rgBindings[2].obLength)  = sizeof(char);

	// Define the DBPARAMS structure.
	params.pData = pData;
	params.cParamSets = 1;
	params.hAccessor = hAcc;

	// Execute the command with paramters.
	hr = pICmdText->Execute(NULL, IID_NULL, &params, &cRowsAffected, NULL);

	// Error handling for the command
	if (FAILED(hr) || (1 != cRowsAffected))
	{
		GetSQLCEErrors(message);
		goto CLEANUP;
		//MessageBox(NULL,"An error occured","error",MB_OK);
	}

CLEANUP:

	// Clean up resources.

	free(pData);
	CoTaskMemFree(rgParamInfo);
	CoTaskMemFree(pNamesBuffer);

	if(pIAcc)   
		pIAcc->Release();
	if(pICmdPrepare) 
		pICmdPrepare->Release();
	if(pICmdWParams) 
		pICmdWParams->Release();
	if(pICmdText)  
		pICmdText->Release();
	if(pIDBCrtCmd)  
		pIDBCrtCmd->Release();

	if(FAILED(hr))
		AtlReportError(__uuidof(DicMgmt),message,IID_IDicMgmt,hr);
	return hr;
}
